package com.loren.demo29.controller;

import com.loren.demo29.data.form.BucketForm;
import com.loren.demo29.service.MinioService;
import com.loren.demo29.utils.MinioUtils;
import io.minio.ObjectStat;
import lombok.AllArgsConstructor;
import org.apache.commons.io.IOUtils;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

@RestController
@AllArgsConstructor
@RequestMapping("/minio")
public class MinioController {

    private final MinioUtils minioUtils;

    private final MinioService minioService;

    private final RestTemplate restTemplate;

    private static final String BUCKET = "bucket-demo-01";

    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");

    @PostMapping
    public String bucket(@RequestBody @Validated BucketForm form) {
        return this.minioService.createBucketInfo(form);
    }

    @PostMapping("/upload")
    public String upload(@RequestParam("file") MultipartFile file, @RequestParam(value = "hello", required = false) String hello) {
        System.out.println(hello);
        String folder = FORMATTER.format(LocalDate.now());
        String filename = file.getOriginalFilename();
        if (filename == null) {
            throw new RuntimeException("filename is blank");
        }
        String object = folder + "/" + filename;
        this.minioUtils.upload(BUCKET, object, file);
        return "success";
    }

    @GetMapping("/upload-disk-1")
    public String uploadDisk1() {
        try {
            String filename = "wallhaven-z859ov.png";
            File file = new File("D:\\document\\wallhaven\\" + filename);
            FileSystemResource fileAsResource = new FileSystemResource(file);
            MultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<>();
            requestParams.add("file", fileAsResource);
            return this.restTemplate.postForObject("http://localhost:8080/minio/upload", requestParams, String.class);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    @GetMapping("/upload-disk-2")
    public String uploadDisk2() {
        try {
            String filename = "wallhaven-kwzpy6.jpg";
            InputStream inputStream = new FileInputStream("D:\\document\\wallhaven\\" + filename);
            ByteArrayResource fileAsResource = new ByteArrayResource(IOUtils.toByteArray(inputStream)) {
                @Override
                public String getFilename() {
                    return filename;
                }
            };
            MultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<>();
            requestParams.add("file", fileAsResource);
            return this.restTemplate.postForObject("http://localhost:8080/minio/upload", requestParams, String.class);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    @PostMapping("/upload-network")
    public String uploadNetwork(@RequestParam("file") MultipartFile file) {
        try {
            ByteArrayResource fileAsResource = new ByteArrayResource(file.getBytes()) {
                @Override
                public String getFilename() {
                    return file.getOriginalFilename();
                }
            };
            MultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<>();
            requestParams.add("file", fileAsResource);
            return this.restTemplate.postForObject("http://localhost:8080/minio/upload", requestParams, String.class);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    @PostMapping("/upload-multi")
    public String upload(@RequestParam("files") MultipartFile[] files) {
        System.out.println(files.length);
        return "success";
    }

    @GetMapping("/upload-origin")
    public String uploadOrigin() {
        String fileParam = "files";
        String uploadUrl = "http://localhost:8080/minio/upload-multi";
        String filename = "wallhaven-z859ov.png";
        File file = new File("D:\\document\\wallhaven\\" + filename);
        InputStream inputStream = null;
        InputStreamReader reader = null;
        BufferedReader bufferedReader = null;
        try {
            String fileName = file.getName();
            URL url = new URL(uploadUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(1000 * 5);
            connection.setRequestMethod("POST");
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(false);
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Charset", "UTF-8");
            String BOUNDARY = "----------" + System.currentTimeMillis();
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);

            OutputStream out = new DataOutputStream(connection.getOutputStream());
            for (int i = 0; i < 2; i++) { // 上传两个文件
                String fileParamContent = "--" + BOUNDARY + "\r\n" +
                        "Content-Disposition: form-data;name=" + fileParam
                        + ";filename=" + fileName
                        + ";filelength=" + file.length()
                        + "\r\n" +
                        "Content-Type:application/octet-stream\r\n\r\n";
                out.write(fileParamContent.getBytes(StandardCharsets.UTF_8));
                DataInputStream dataStream = new DataInputStream(new FileInputStream(file));
                int bytes;
                byte[] bufferOut = new byte[1024];
                while ((bytes = dataStream.read(bufferOut)) != -1) {
                    out.write(bufferOut, 0, bytes);
                }
                out.write("\r\n".getBytes(StandardCharsets.UTF_8));
                dataStream.close();
            }
            out.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes(StandardCharsets.UTF_8));
            out.flush();
            out.close();

            StringBuilder inBuilder = new StringBuilder();
            inputStream = connection.getInputStream();
            reader = new InputStreamReader(inputStream);
            bufferedReader = new BufferedReader(reader);
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                inBuilder.append(line).append("\r\n");
            }
            connection.disconnect();
            return inBuilder.substring(0, inBuilder.length() - 1);
        } catch (Exception e) {
            System.err.println(e.getMessage());
        } finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                if (reader != null) {
                    reader.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (Exception e2) {
                System.err.println(e2.getMessage());
            }
        }
        return "success";
    }

    /**
     * 不建议用这种下载方式
     */
    @GetMapping("/{bucket}/{folder}/{filename}")
    public void download(@PathVariable("bucket") String bucket, @PathVariable("folder") String folder,
                         @PathVariable("filename") String filename, HttpServletResponse response) throws IOException {
        String object = folder + "/" + filename;
        ObjectStat objectStat = this.minioUtils.statObject(bucket, object);
        response.setContentType(objectStat.contentType());
        response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name()));
        InputStream inputStream = this.minioUtils.getObject(bucket, object);
        IOUtils.copy(inputStream, response.getOutputStream());
        inputStream.close();
    }

    /**
     * 推荐的下载方式
     */
    @GetMapping("/v2/{bucket}/{folder}/{filename}")
    public ResponseEntity<byte[]> download2(@PathVariable("bucket") String bucket, @PathVariable("folder") String folder,
                                            @PathVariable("filename") String filename, HttpServletResponse response) throws IOException {
        String object = folder + "/" + filename;

        InputStream inputStream = this.minioUtils.getObject(bucket, object);
        if (inputStream == null) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }

        byte[] fileData = IOUtils.toByteArray(inputStream);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", filename);

        return new ResponseEntity<>(fileData, headers, HttpStatus.OK);
    }
}
